// Memory Leak Prevention
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h>
#define LEAK_LINE -1L

#include <iostream>
using namespace std;
#include <windows.h>
#include <ctime>

#include "ConsoleColor.h"
using namespace COLOR;
#include "ZoneManager.h"
#include "Game.h"
#include "Zone.h"
#include "Player.h"

// Global Variables:

// the array I will be making here will be used to identify the size of the map, and where each peice will be.
// I will need to later on find out a good way to fill in the info into the array so that it doesnt mes with the game.
// my thought is to make a rand() run through a sqrt() while using % to thin it down to what I want. may use my current equation to test it out first...

// Variables moved to Game class

// float Length;
// float MapSizeSqrd;

//-------------------------------------\\
//--------Testing purposes ONLY--------\\
//=====================================\\

void FindOutIfRandomMapWorks(Player &tempPlayer);

//=====================================\\
//--------Testing purposes ONLY--------\\
//-------------------------------------\\

// Prototypes:

int main();
int DieRolls(int SizeOfDie);
char *MakeMap();
int LengthOfGame();
int WorldGenerator();
int RandomStoryGenerator(int Length);
void StoryPieces(int StoryPart, int StoryParts[]);
bool WorldCheck(int WorldPiece);
bool StoryCheck(int StoryPiece);
void MapArrayMaker();
void NewGame();
int FirstCheckForPathNeeded(int direction, Zone* currZone);
int CheckForPathNeeded(int direction, Zone* currZone, int depth);
int DetermineZoneType(Zone* pZone, int depth);
void InGameMenu(Player &tempPlayer);
bool PossiblePlayerZone(Player &tempPlayer, int Value);

#define MAX_DEPTH 3

// will need to remember the procedure for getting info from a .cpp to here...
// quick note: look at the texts from malcolm on how to make a good array.
// also asked him about save data. hope he has something I can use...

int main()
{
	srand(unsigned int(time(0)));
	rand();

	MapArrayMaker();

	Game* pGame = Game::GetInstance();
	ZoneManager* pZoneManager = ZoneManager::GetInstance();

	// Initalize
	pGame->Initialize();
	pZoneManager->Initialize();

	NewGame();

	//while( true )
	{
		// Input

		// Update

		// Render (note: render will display text)
	}
	

	// Shutdown
	pZoneManager->Shutdown();
	pGame->Shutdown();

	cout << "\n\n";
	system("pause");
	return 1;
}

int DieRolls(int SizeOfDie)
{
	// need the SizeOfDie for the size. D6, D20, D4, ext.

	int DieRoll = (rand() % SizeOfDie + 1);

	return DieRoll;

}

void MapArrayMaker()
{
	// This for statement HAS to make the map array correctly. May move it to its own function because it is only needed once. 
	// First make it. going with the 1-11, 2-22, etc. not center = 1. need to figure that one out.
	Game *pGame = Game::GetInstance();
	ZoneManager* pZoneManager = ZoneManager::GetInstance();
	for(unsigned int x = 0; x < pZoneManager->GetWorldSize(); x++)
	{
		for(unsigned int y = 0; y < pZoneManager->GetWorldSize(); y++)
		{
			pGame->SetWorldMap(x, y, x * pZoneManager->GetWorldSize() + y + 1);
		}
	}
}

void NewGame()
{
	//LengthOfGame();
	WorldGenerator();
	Player Bob;
	Bob.SetPlayerPosition();
	InGameMenu(Bob);
}


void FindOutIfRandomMapWorks(Player &tempPlayer)
{

	Game* pGame = Game::GetInstance();
	ZoneManager* pZoneManager = ZoneManager::GetInstance();
	Zone* pZone;
	float PlayerPosition = (tempPlayer.GetPlayerPositionY() * pZoneManager->GetWorldWidth() + tempPlayer.GetPlayerPositionX());

	for(unsigned int x = 0; x < pZoneManager->GetWorldSize(); x++)
	{
		if(x % pZoneManager->GetWorldSize() == 0)
			cout << '\n';
		pZone = pZoneManager->GetZone(x);
		switch(pZone->GetZoneType())
		{
		case 0:
			cout << DARK_RED;
			break;
		case 1:
			cout << GREEN;
			break;
		case 2:
			cout << BLUE;
			break;
		case 3:
			cout << DARK_GREEN;
			break;
		case 4:
			cout << DARK_TAN;
			break;
		default:
			cout << WHITE;
			break;
		}
		if(x != PlayerPosition)
		{
			cout << "[";
			cout << pZone->GetZoneType();
		}
		else
		{
			cout << YELLOW << "[P";
		}
		cout << "] ";
		cout << WHITE;
	}
}

int WorldGenerator()
{
	// need to use this for the random story, and random map layout. later on will need to work in a random location generator.
	// have to make sure that the locations are connected properly. will have to make a check for that.

	// need to use the length of the game to modify the size of the world. When I can do that, I will have to call upon the story generator...
	// have to set up a set of generic world peices, set values for them, and so forth. sounds like a need for a class...
	// may need a class for the story parts as well...

	// note to self: the class can have 4 bool variables. one for each direction, north, south, east and west. do a check to see if bool north = 1, and bool south of the northern peice = 1.
	// retrurn 1 if it works.
	Game *pGame = Game::GetInstance();
	ZoneManager *pZoneManager = ZoneManager::GetInstance();
	int StartLocationA, StartLocationB;
	pZoneManager->SetWorldSize(20, 20);

	StartLocationA = rand() % pZoneManager->GetWorldHeight();						// randomly choosing a pieces of the map to start at. any point works.
	StartLocationB = rand() % pZoneManager->GetWorldWidth();						// just need some point to start off with.

	pZoneManager->CreateWorld();
	Zone* pZone;
	pZoneManager->SetWaterLimit();
	unsigned int nZoneType;
	for(unsigned int x = 0; x < pZoneManager->GetWorldSize(); x++)
	{
		pZone = pZoneManager->GetZone(x);
		for(;;)
		{
			nZoneType = (ZONE_TYPE)rand()%(ZONE_MAX);
			if(nZoneType == 2 && pZoneManager->GetWaterLimit() != 0)
			{
				pZoneManager->AddToWaterLimit();
				pZone->SetZoneType(nZoneType);
				break;
			}
			else if(nZoneType != 2)
			{
				pZone->SetZoneType(nZoneType);
				break;
			}
		}
	}

	//FindOutIfRandomMapWorks();

	//cout << "\n\n\n";

	int zoneType = 0;
	for(unsigned int x = 0; x < pZoneManager->GetWorldSize(); x++)
	{
		pZone = pZoneManager->GetZone(x);
		zoneType = pZone->GetZoneType();

		if( zoneType )
		{
			// FirstCheckForPathNeeded(NORTH, pZone);
			// FirstCheckForPathNeeded(SOUTH, pZone);
			// FirstCheckForPathNeeded(EAST, pZone);
			// FirstCheckForPathNeeded(WEST, pZone);

			DetermineZoneType(pZone, 0);
		}
	}

	return 1;
}
/*
int FirstCheckForPathNeeded(int direction, Zone* currZone)
{
	Zone* pZone = NULL;
	pZone = currZone->GetZoneNeighbor(direction);

	Zone* otherZones = NULL;
	
	switch( direction )
	{
	case NORTH:
		{
			otherZones = currZone->GetZoneNeighbor(SOUTH);

			if( otherZones )
			{
				if( otherZones->GetZoneType() )
				{
					return otherZones->GetZoneType();
				}
			}
		}
		break;
	case SOUTH:
		{
			otherZones = currZone->GetZoneNeighbor(NORTH);

			if( otherZones )
			{
				if( otherZones->GetZoneType() )
				{
					return otherZones->GetZoneType();
				}
			}
		}
		break;
	case EAST:
		{
			otherZones = currZone->GetZoneNeighbor(WEST);

			if( otherZones )
			{
				if( otherZones->GetZoneType() )
				{
					return otherZones->GetZoneType();
				}
			}
		}
		break;
	case WEST:
		{
			otherZones = currZone->GetZoneNeighbor(EAST);

			if( otherZones )
			{
				if( otherZones->GetZoneType() )
				{
					return otherZones->GetZoneType();
				}
			}
		}
		break;
	}

	if(pZone)
	{
		if( pZone->GetZoneType() )
		{
			return pZone->GetZoneType();
		}
		else
		{
			int neighborType = 0;
			for(unsigned int i = 1; i <= 8; i*=2)
			{
				int returnType = CheckForPathNeeded(i, pZone, 1);

				if( returnType )
					neighborType = returnType;
			}

			if( neighborType )
			{
				pZone->SetZoneType(neighborType);
			}

			return neighborType;
		}
	}

	return 0;
}

int CheckForPathNeeded(int direction, Zone* currZone, int depth)
{
	Zone* pZone = NULL;
	pZone = currZone->GetZoneNeighbor(direction);
	
	if( depth > MAX_DEPTH )
		return currZone->GetZoneType();

	if(pZone)
	{
		if( pZone->GetZoneType() )
		{
			return pZone->GetZoneType();
		}
		else
		{
			int neighborType = CheckForPathNeeded(direction, pZone, depth+1);

			if( neighborType )
			{
				pZone->SetZoneType(neighborType);
			}

			return neighborType;
		}
	}

	return 0;
}
*/
int DetermineZoneType(Zone* pZone, int depth)
{
	int ValidNeighbors = 0;

	Zone* pNorth = pZone->GetZoneNeighbor(NORTH);
	Zone* pSouth = pZone->GetZoneNeighbor(SOUTH);
	Zone* pEast = pZone->GetZoneNeighbor(EAST);
	Zone* pWest = pZone->GetZoneNeighbor(WEST);
	
	if(pNorth)
	{
		if(pNorth->GetZoneType() == 1)
			ValidNeighbors++;
	}
	if(pSouth)
	{
		if(pSouth->GetZoneType() == 1)
			ValidNeighbors++;
	}
	if(pEast)
	{
		if(pEast->GetZoneType() == 1)
			ValidNeighbors++;
	}
	if(pWest)
	{
		if(pWest->GetZoneType() == 1)
			ValidNeighbors++;
	}

	if(ValidNeighbors > 1)
		return 0;
	
	if(depth < MAX_DEPTH)
	{
		int ReturnCount = 0;
		if(pNorth)
			ReturnCount += DetermineZoneType(pNorth, depth + 1);

		if(pSouth)
			ReturnCount += DetermineZoneType(pSouth, depth + 1);

		if(pEast)
			ReturnCount += DetermineZoneType(pEast, depth + 1);

		if(pWest)
			ReturnCount += DetermineZoneType(pWest, depth + 1);

		if(ReturnCount)
			return 1;
		else
			return 0;
	}

	return 1;
}

void InGameMenu(Player &tempPlayer)
{
	
	int tempChoice;
	for(;;)
	{
		//InGameScreen(tempPlayer);
		FindOutIfRandomMapWorks(tempPlayer);

		cout << "\n\n";
		cout << "1. Move North  2. Move South  3. Move West   4. Move East  \n";
		cout << "5. Talk To...  6. Attack...   7. Inventory   8. Look Around\n";
		cout << "9. Stats Page 10. Save Game  11. Load Game  12. Exit Game  \n\n";
		cout << "What would you like to do? ";

		for(;;)
		{	
			if(cin >> tempChoice && tempChoice >= 1 && tempChoice < 13)
			{
				cin.clear();
				cin.ignore(INT_MAX, '\n');
				break;
			}
			cin.clear();
			cin.ignore(INT_MAX, '\n');
		}
		
		switch(tempChoice)
		{
		case 1:
			if(PossiblePlayerZone(tempPlayer, NORTH))
				tempPlayer.SetY(-1);
			break;
		case 2:
			if(PossiblePlayerZone(tempPlayer, SOUTH))
				tempPlayer.SetY(1);
			break;
		case 3:
			if(PossiblePlayerZone(tempPlayer, WEST))
				tempPlayer.SetX(-1);
			break;
		case 4:
			if(PossiblePlayerZone(tempPlayer, EAST))
				tempPlayer.SetX(1);
			break;
		case 5:
			break;
		case 6:
			break;
		case 7:
			break;
		case 8:
			break;
		case 9:
			break;
		case 10:
			break;
		case 11:
			break;
		}
		if(tempChoice == 12)
		{
		//	bool save;
		//	cout << "Would you like to save your game first? (1-y, 0-n) ";
		//	
		//	for(;;)
		//	{	
		//		if(cin >> save)
		//		{
		//			cin.clear();
		//			cin.ignore(INT_MAX, '\n');
		//			break;
		//		}
		//		cin.clear();
		//		cin.ignore(INT_MAX, '\n');
		//	}
		//	
		//	if(save)
		//	{
		//		tempPlayer.Save();
		//	}
			break;
		}
		system("cls");
	}
}

bool PossiblePlayerZone(Player &tempPlayer, int Value)
{
	ZoneManager *pManager = ZoneManager::GetInstance();
	float PlayerLocationY = tempPlayer.GetPlayerPositionY();
	float PlayerLocationX = tempPlayer.GetPlayerPositionX();
	float PlayerLocation = PlayerLocationY * pManager->GetWorldWidth() + PlayerLocationX;
	Zone *pZone = pManager->GetZone(PlayerLocation);

	return pZone->CheckNeighbor(Value);
}